<template>
  <div ref="diagramDiv" class="diagram-container"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, watch, nextTick } from "vue";
import * as go from "gojs";

interface DiagramProps {
  nodeDataArray: any[];
  canvasSettings: {
    scale: number
    backgroundColor: string
  }
  styleSettings: {
    borderColor: string
    borderWidth: number
    fontColor: string
    fontSize: number
    fontFamily: string
    showArrow: boolean
    fontWeight: string
  }
  nodeSettings: {
    rootNodeWidth: number
    normalNodeWidth: number
    nodeSpacing: number
    linkWidth: number
    normalNodeHeight: number
    linkHeight: number // 添加连接线高度属性
    arrowWidth: number
  }
}

const props = defineProps<DiagramProps>()
const emit = defineEmits(['diagramReady'])

const diagramDiv = ref<HTMLDivElement>()
let diagram: go.Diagram | null = null

// 添加防抖变量
let styleUpdateTimer: NodeJS.Timeout | null = null
let layoutUpdateTimer: NodeJS.Timeout | null = null

onMounted(() => {
  initDiagram()
})

// 分别监听不同类型的变化
watch(() => props.nodeDataArray, () => {
  updateDiagramData()
}, { deep: true })

// 只监听缩放变化
watch(() => props.canvasSettings.scale, (newScale) => {
  updateScale(newScale)
})

// 监听纯样式变化（不需要重新渲染的样式）
watch(() => [
  props.styleSettings.borderColor,
  props.styleSettings.fontColor,
  props.styleSettings.showArrow,
  props.nodeSettings.linkWidth,
  props.nodeSettings.arrowWidth
], () => {
  // 防抖处理
  if (styleUpdateTimer) {
    clearTimeout(styleUpdateTimer)
  }
  styleUpdateTimer = setTimeout(() => {
    updateStylesOnly()
  }, 100)
}, { deep: true })

// 监听需要重新渲染的样式变化
watch(() => [
  props.styleSettings.borderWidth,
  props.styleSettings.fontSize,
  props.styleSettings.fontFamily,
  props.styleSettings.fontWeight,
  props.canvasSettings.backgroundColor
], () => {
  // 防抖处理
  if (styleUpdateTimer) {
    clearTimeout(styleUpdateTimer)
  }
  styleUpdateTimer = setTimeout(() => {
    updateStylesOnly()
  }, 100)
}, { deep: true })

// 监听布局相关变化（需要重新布局但不重新创建模型）
watch(() => [
  props.nodeSettings.rootNodeWidth,
  props.nodeSettings.normalNodeWidth,
  props.nodeSettings.nodeSpacing,
  props.nodeSettings.normalNodeHeight,
  props.nodeSettings.linkHeight
], () => {
  // 防抖处理
  if (layoutUpdateTimer) {
    clearTimeout(layoutUpdateTimer)
  }
  layoutUpdateTimer = setTimeout(() => {
    updateLayoutOnly()
  }, 150)
}, { deep: true })

const initDiagram = () => {
  if (!diagramDiv.value) return

  const $ = go.GraphObject.make

  diagram = $(go.Diagram, diagramDiv.value, {
    'undoManager.isEnabled': true,
    layout: $(go.TreeLayout, {
      angle: 90,
      layerSpacing: props.nodeSettings.linkHeight, // 使用连接线高度控制层级间距
      nodeSpacing: props.nodeSettings.nodeSpacing,
      arrangement: go.TreeLayout.ArrangementHorizontal
    }),
    initialScale: props.canvasSettings.scale / 100,
    allowZoom: true,
    allowHorizontalScroll: true,
    allowVerticalScroll: true
  })

  createNodeTemplate()
  createLinkTemplate()
  updateDiagramData()
  emit('diagramReady', diagram)
}

const createNodeTemplate = () => {
  if (!diagram) return

  const $ = go.GraphObject.make

  // 创建节点模板，使用更直接的宽度控制方式
  diagram.nodeTemplate = $(go.Node, 'Auto',
    {
      selectable: true,
      resizable: false
    },
    $(go.Shape, 'Rectangle',
      {
        name: 'SHAPE', // 添加名称以便查找
        fill: 'white',
        stroke: props.styleSettings.borderColor,
        strokeWidth: props.styleSettings.borderWidth,
        minSize: new go.Size(50, 50), // 最小尺寸
        maxSize: new go.Size(500, 500)  // 最大尺寸
      },
      // 直接绑定宽度到 level
      new go.Binding('desiredSize', 'level', (level) => {
        if (level === 0) {
          // 顶级节点：水平显示，宽度大，高度固定
          const width = props.nodeSettings.rootNodeWidth
          return new go.Size(width, 40)
        } else {
          // 普通节点：垂直显示，宽度较小，高度根据文本长度动态调整
          const width = props.nodeSettings.normalNodeWidth // 使用 normalNodeWidth 而不是固定值
          const height = props.nodeSettings.normalNodeHeight
          return new go.Size(width, height)
        }
      })
    ),
    $(go.TextBlock,
      {
        name: 'TEXT',
        margin: new go.Margin(5, 8, 5, 8), // 减少边距以适应垂直文本
        font: `${props.styleSettings.fontWeight} ${props.styleSettings.fontSize}px ${props.styleSettings.fontFamily}`,
        stroke: props.styleSettings.fontColor,
        textAlign: 'center',
        verticalAlignment: go.Spot.Center,
        wrap: go.TextBlock.None, // 禁用自动换行，我们手动控制
        overflow: go.TextBlock.OverflowEllipsis
      },
      new go.Binding('text', 'text'),
      // 根据节点级别设置文本方向
      new go.Binding('text', '', (data) => {
        if (data.level === 0) {
          // 顶级节点：正常水平显示
          return data.text
        } else {
          // 普通节点：垂直显示，每个字符用换行符分隔
          // 去除前后空格，然后每个字符一行
          const cleanText = data.text.trim()
          return cleanText.split('').join('\n')
        }
      }),
      new go.Binding('maxLines', 'level', (level) => {
        return level === 0 ? 1 : 20 // 普通节点允许更多行以适应垂直文本
      })
    )
  )
}

const createLinkTemplate = () => {
  if (!diagram) return

  const $ = go.GraphObject.make

  diagram.linkTemplate = $(go.Link,
    {
      routing: go.Link.Orthogonal,
      corner: 5,
      selectable: false,
      fromSpot: go.Spot.Right,
      toSpot: go.Spot.Left
    },
    $(go.Shape,
      {
        stroke: props.styleSettings.borderColor,
        strokeWidth: props.nodeSettings.linkWidth // 只使用linkWidth控制连接线粗细
      }
    ),
    $(go.Shape,
      {
        toArrow: props.styleSettings.showArrow ? 'Standard' : '',
        strokeWidth: props.nodeSettings.arrowWidth,
        stroke: props.styleSettings.borderColor,
        fill: props.styleSettings.borderColor
      }
    )
  )
}

const updateDiagramData = () => {
  if (!diagram) return

  const nodeDataArray = buildTreeData(props.nodeDataArray)
  const linkDataArray = buildLinkData(nodeDataArray)
  diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray)

  nextTick(() => {
    diagram?.layoutDiagram(true)
  })
}

// 单独的缩放更新函数
const updateScale = (newScale: number) => {
  if (!diagram) return
  diagram.scale = newScale / 100
}

const updateStylesOnly = () => {
  if (!diagram) return

  // 直接更新现有模板的样式，不重新创建模型
  try {
    // 更新所有节点的样式和尺寸
    diagram.nodes.each((node) => {
      const shape = node.findObject('SHAPE') as go.Shape
      const text = node.findObject('TEXT') as go.TextBlock
      const level = node.data.level

      if (shape) {
        shape.stroke = props.styleSettings.borderColor
        shape.strokeWidth = props.styleSettings.borderWidth

        // 更新节点尺寸
        if (level === 0) {
          // 顶级节点：水平显示，宽度大，高度固定
          const width = props.nodeSettings.rootNodeWidth
          shape.desiredSize = new go.Size(width, 40)
        } else {
          // 普通节点：垂直显示，宽度较小，高度根据设置调整
          const width = props.nodeSettings.normalNodeWidth // 使用 normalNodeWidth 而不是固定值
          const height = props.nodeSettings.normalNodeHeight
          shape.desiredSize = new go.Size(width, height)
        }
      }

      if (text) {
        text.stroke = props.styleSettings.fontColor
        text.font = `${props.styleSettings.fontWeight} ${props.styleSettings.fontSize}px ${props.styleSettings.fontFamily}`

        // 更新文本内容（垂直显示）
        if (level === 0) {
          // 顶级节点：正常水平显示
          text.text = node.data.text
        } else {
          // 普通节点：垂直显示，每个字符用换行符分隔
          const cleanText = node.data.text.trim()
          text.text = cleanText.split('').join('\n')
        }
      }
    })

    // 更新所有连接线的样式
    diagram.links.each((link) => {
      // 更新连接线主体
      const mainShape = link.elt(0) as go.Shape
      if (mainShape) {
        mainShape.stroke = props.styleSettings.borderColor
        mainShape.strokeWidth = props.nodeSettings.linkWidth
      }

      // 更新箭头
      const arrowShape = link.elt(1) as go.Shape
      if (arrowShape) {
        arrowShape.stroke = props.styleSettings.borderColor
        arrowShape.fill = props.styleSettings.borderColor
        arrowShape.strokeWidth = props.nodeSettings.arrowWidth

        if (props.styleSettings.showArrow) {
          arrowShape.toArrow = 'Standard'
        } else {
          arrowShape.toArrow = ''
        }
      }
    })

    // 平滑更新布局
    nextTick(() => {
      if (diagram) {
        diagram.updateAllTargetBindings()
      }
    })
  } catch (error) {
    console.error('样式更新失败，回退到完全重新渲染:', error)
    updateDiagramStyles()
  }
}

const updateLayoutOnly = () => {
  if (!diagram) return

  // 更新布局间距
  const layout = diagram.layout as go.TreeLayout
  layout.nodeSpacing = props.nodeSettings.nodeSpacing
  layout.layerSpacing = props.nodeSettings.linkHeight // 使用连接线高度控制层级间距

  // 更新所有节点的尺寸
  let updatedNodes = 0
  diagram.nodes.each((node) => {
    const shape = node.findObject('SHAPE') as go.Shape
    const text = node.findObject('TEXT') as go.TextBlock
    const level = node.data.level

    if (shape) {
      // 更新节点尺寸
      if (level === 0) {
        // 顶级节点：水平显示，宽度大，高度固定
        const width = props.nodeSettings.rootNodeWidth
        shape.desiredSize = new go.Size(width, 40)
      } else {
        // 普通节点：垂直显示，宽度较小，高度根据设置调整
        const width = props.nodeSettings.normalNodeWidth // 使用 normalNodeWidth 而不是固定值
        const height = props.nodeSettings.normalNodeHeight
        shape.desiredSize = new go.Size(width, height)
      }
      updatedNodes++
    }

    if (text) {
      // 更新文本内容（垂直显示）
      if (level === 0) {
        // 顶级节点：正常水平显示
        text.text = node.data.text
      } else {
        // 普通节点：垂直显示，每个字符用换行符分隔
        const cleanText = node.data.text.trim()
        text.text = cleanText.split('').join('\n')
      }
    }
  })

  // 重新布局
  nextTick(() => {
    if (diagram) {
      diagram.layoutDiagram(true)
    }
  })
}

const updateDiagramStyles = () => {
  if (!diagram) return

  // 保存当前缩放和数据
  const currentScale = diagram.scale
  const currentModel = diagram.model as go.GraphLinksModel

  // 先保存当前的数据，避免数据丢失
  const nodeData = currentModel.nodeDataArray.slice() // 创建副本
  const linkData = currentModel.linkDataArray.slice() // 创建副本

  // 重新创建模板
  createNodeTemplate()
  createLinkTemplate()

  // 使用保存的数据重新创建模型
  diagram.model = new go.GraphLinksModel(nodeData, linkData)

  // 恢复缩放并重新布局
  nextTick(() => {
    if (diagram) {
      diagram.scale = currentScale
      diagram.layoutDiagram(true)
    }
  })
}

const buildTreeData = (inputData: any[]) => {
  const nodes: any[] = []
  const levelMap: { [key: number]: string[] } = {}

  // 按层级分组数据
  inputData.forEach((item, index) => {
    const level = getIndentLevel(item.text)
    if (!levelMap[level]) {
      levelMap[level] = []
    }
    levelMap[level].push(item.text.trim())
  })

  // 构建节点数据
  let nodeId = 0
  const nodeMap: { [key: string]: number } = {}

  Object.keys(levelMap).sort((a, b) => parseInt(a) - parseInt(b)).forEach(level => {
    levelMap[parseInt(level)].forEach(text => {
      const cleanText = text.trim()
      if (cleanText) {
        const nodeLevel = parseInt(level)
        nodes.push({
          key: nodeId,
          text: cleanText,
          level: nodeLevel
        })
        nodeMap[cleanText] = nodeId
        nodeId++
      }
    })
  })

  return nodes
}

const buildLinkData = (nodes: any[]) => {
  const links: any[] = []
  const levelGroups: { [key: number]: any[] } = {}

  // 按层级分组节点
  nodes.forEach(node => {
    if (!levelGroups[node.level]) {
      levelGroups[node.level] = []
    }
    levelGroups[node.level].push(node)
  })

  // 构建连接关系
  const levels = Object.keys(levelGroups).map(l => parseInt(l)).sort((a, b) => a - b)

  for (let i = 0; i < levels.length - 1; i++) {
    const currentLevel = levels[i]
    const nextLevel = levels[i + 1]

    const currentNodes = levelGroups[currentLevel]
    const nextNodes = levelGroups[nextLevel]

    if (currentLevel === 0) {
      // 根节点连接到所有第一级节点
      const rootNode = currentNodes[0]
      nextNodes.forEach(node => {
        links.push({
          from: rootNode.key,
          to: node.key
        })
      })
    } else {
      // 其他层级的连接逻辑（简化处理）
      let currentParentIndex = 0
      const nodesPerParent = Math.ceil(nextNodes.length / currentNodes.length)

      nextNodes.forEach((node, index) => {
        const parentIndex = Math.floor(index / nodesPerParent)
        if (parentIndex < currentNodes.length) {
          links.push({
            from: currentNodes[parentIndex].key,
            to: node.key
          })
        }
      })
    }
  }

  return links
}

const getIndentLevel = (text: string): number => {
  const match = text.match(/^(\s*)/)
  return match ? Math.floor(match[1].length / 2) : 0
}

// 导出图片功能
const exportImage = (format: 'PNG' | 'JPEG' = 'PNG') => {
  if (!diagram) return null

  return diagram.makeImageData({
    background: props.canvasSettings.backgroundColor,
    returnType: format.toLowerCase(),
    size: new go.Size(NaN, NaN)
  })
}

// 全屏功能
const toggleFullscreen = () => {
  if (!diagramDiv.value) return

  if (document.fullscreenElement) {
    document.exitFullscreen()
  } else {
    diagramDiv.value.requestFullscreen()
  }
}

defineExpose({
  exportImage,
  toggleFullscreen,
  diagram,
  // 添加测试函数
  testLayoutUpdate: () => {
    updateLayoutOnly()
  }
})
</script>

<style scoped>
.diagram-container {
  width: 100%;
  height: 100%;
  background: #f8f9fa;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  overflow: hidden;
}
</style>
